﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Cms.Domain
{
    public class MenuVersion : ICloneable, IComparable<MenuVersion>
    {
        private Administrator _editedBy;
        private IList<MenuItem> _items;
        private string _timestamp;

        public MenuVersion()
        {
            _items = new List<MenuItem>();
        }

        private MenuVersion(MenuVersion original)
            : this()
        {
            _editedBy = original.EditedBy;
            _timestamp = original.Timestamp;
            AddItems(null, original.GetRootItems());
        }
        
        public virtual int ID { get; set; }
        
        public virtual string Timestamp
        {
            get { return _timestamp; }
            set { _timestamp = value; }
        }

        public virtual Administrator EditedBy
        {
            get { return _editedBy; }
            set { _editedBy = value; }
        }
        
        public virtual Menu Parent { get; set; }

        public virtual IList<MenuItem> Items
        {
            get { return _items; }
            set { _items = value; }
        }

        #region ICloneable Members

        public virtual object Clone()
        {
            return new MenuVersion(this);
        }

        #endregion

        public virtual IList<MenuItem> GetRootItems()
        {
            return _items.Where(mi => mi.Parent == null).ToList();
        }

        public virtual MenuItem GetItem(int id)
        {
            return _items.FirstOrDefault(mi => mi.ID == id);
        }

        public virtual bool CanItemBeNamedAndMovedTo(int id, int localeID, string name, MenuItem parent)
        {
            IList<MenuItem> parentLevelItems = parent == null ? GetRootItems() : parent.SubItems;
            return
                parentLevelItems.All(mi => mi.GetTranslation(localeID).Name.ToLower() != name.ToLower() || mi.ID == id);
        }

        public virtual void UpdateSortIndexes()
        {
            PerformSortIndexUpdate(GetRootItems());
        }
        
        protected virtual void PerformSortIndexUpdate(IEnumerable<MenuItem> items)
        {
            int i = 0;
            foreach (MenuItem mi in items)
            {
                PerformSortIndexUpdate(mi.SubItems);
                mi.SortIndex = i;
                i++;
            }
        }
        
        private void AddItems(MenuItem parent, IEnumerable<MenuItem> originalItems)
        {
            MenuItem clone;
            foreach (MenuItem mi in originalItems)
            {
                clone = (MenuItem)mi.Clone();
                clone.Parent = parent;
                if (clone.Parent != null)
                    clone.Parent.SubItems.Add(clone);
                clone.Version = this;
                _items.Add(clone);
                AddItems(clone, mi.SubItems);
            }
        }

        public virtual int CompareTo(MenuVersion other)
        {
            return this.ID > 0 && this.ID == other.ID ? 0 : 1;
        }

        public override bool Equals(object obj)
        {
            MenuVersion other = (MenuVersion)obj;
            if (this.ID != other.ID)
                return false;
            if (this.ID > 0 && this.ID == other.ID)
                return true;
            return ReferenceEquals(this, obj);
        }

        public override int GetHashCode()
        {
            return this.ID.GetHashCode();
        }
    }
}